抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Public Key

1. 题目

Recall that an address is the last 20 bytes of the keccak-256 hash of the address’s public key.

To complete this challenge, find the public key for the owner‘s account.

源码

1
2
3
4
5
6
7
8
9
10
11
12
pragma solidity ^0.4.21;

contract PublicKeyChallenge {
address owner = 0x92b28647ae1f3264661f72fb2eb9625a89d88a31;
bool public isComplete;

function authenticate(bytes publicKey) public {
require(address(keccak256(publicKey)) == owner);

isComplete = true;
}
}

2. 分析

按题目的意思来,owner应该就是合约的部署者,我们要从交易中获取公钥,而地址的计算公式为address = address(keccak256(publicKey)),所以只要从交易中还原出 publicKey即可。

因为Ropsten 网络已经停用,所以要复现该题只能对合约进行修改了,将owner修改为本地账户

1
2
3
4
5
6
7
8
9
10
11
pragma solidity ^0.4.21;

contract PublicKeyChallenge {
address owner = 0xfDc84b042c01F01C7cC6eF08452BA156844c3A5C; // 本地账户
bool public isComplete;

function authenticate(bytes publicKey) public {
require(address(keccak256(publicKey)) == owner);
isComplete = true;
}
}

本人自己琢磨了很久,自己写出来的一个脚本,用于通过 txhash获取公钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { ethers } from "ethers";

// provider
const connection = "";
const provider = new ethers.providers.JsonRpcProvider(connection);

// 交易的hash
const txHash = "";

// 获取交易信息
const transaction = await provider.getTransaction(txHash);
// console.log(`transaction => `,transaction); //打印交易详情

// txData 对象内的字段缺一不可
const txData = {
// gasPrice: transaction.gasPrice, // 这个不需要,否则会报错
gasLimit: transaction.gasLimit,
value: transaction.value,
nonce: transaction.nonce,
data: transaction.data,
to: transaction.to,
chainId: transaction.chainId,
type: transaction.type,
maxFeePerGas: transaction.maxFeePerGas,
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas,
}

// 对txData交易对象序列化为其原始二进制格式
const signingData = ethers.utils.serializeTransaction(txData);

// 对序列化后的交易对象进行hash
const msgHash = ethers.utils.keccak256(signingData);

// 获取交易详情中的 r s v
const signature = {r: transaction.r, s: transaction.s, v: transaction.v};

// 获取原生未压缩的公钥,即 0x04 开头的
let rawPublicKey = ethers.utils.recoverPublicKey(msgHash, signature);
console.log(rawPublicKey);


// 把开头的 0x04 字段删掉 ===》 将 `0x04` 替换成 `0x`
rawPublicKey = `0x${rawPublicKey.slice(4)}`;
console.log(rawPublicKey);

3. 解题

部署challenge,通过脚本计算出公钥

![image-20240412145137751](Public Key/image-20240412145137751.png)

调用hacker中的attack()函数

![image-20240412145149249](Public Key/image-20240412145149249.png)

解题成功~

评论



政策 · 统计 | 本站使用 Volantis 主题设计